/*
Copyright (c) 2025 HeZongLun
NahidaProject is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan
PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/

#include "Logger.h"

#include<stdexcept>
#include<iostream>
#include<stdarg.h>
#include<string.h>
#include<time.h>
#include<mutex>

NahidaProject::Logger * NahidaProject::Logger::instance=nullptr;
const char * NahidaProject::Logger::level[LEVEL_COUNT]={ "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};

NahidaProject::Logger::Logger() : length(0), max(0),levels(DEBUG)
{

}

NahidaProject::Logger::~Logger()
{
    Close();
}

void NahidaProject::Logger::Open(const std::string &fileName)
{
    this->fileName = fileName;
    fileOut.open(fileName,std::ios::app);
    if(fileOut.fail())
    {
        throw std::logic_error("open file failed "+fileName);
    }
	fileOut.seekp(0,std::ios::end);
    length= fileOut.tellp();
}

void NahidaProject::Logger::Close()
{
	fileOut.close();
}

NahidaProject::Logger * NahidaProject::Logger::GetInstance()
{
    if(instance==nullptr)
    {
        std::mutex mtx;
        mtx.lock();
        instance=new Logger();
        mtx.unlock();
    }
    return instance;
}

void NahidaProject::Logger::Log(Level level,const char *fileName,int line,const char *format,...){
    if(levels > level){
        return;
    }
    if (fileOut.fail()){
        throw std::logic_error("open file failed "+ this->fileName);
    }

    auto timeTicks=time(nullptr);
    auto ptns=localtime(&timeTicks);
    char timeArray[32];
    memset(timeArray,0,sizeof(timeArray));
    strftime(timeArray,sizeof(timeArray),"[%Y-%m-%d %H:%M:%S]",ptns);

    const char *fmt="%s [%s] %s[LINE %d]";
    int size = snprintf(nullptr, 0, fmt, timeArray, this->level[level],fileName,line);
    if(size > 0) {
        char *buffer=new char[size+1];
		memset(buffer, 0, static_cast<size_t>(size) + 1);
		snprintf(buffer, static_cast<size_t>(size) + 1, fmt, timeArray, this->level[level], fileName, line);
        std::cout << buffer;
		fileOut << buffer;
        length += size;
        delete []buffer;
    }

    va_list arg_ptr;
    va_start(arg_ptr, format);
    size=vsnprintf(nullptr, 0, format,arg_ptr);
    va_end(arg_ptr);
    if(size > 0){
        char *content=new char[size+1];
        va_start(arg_ptr, format);
		vsnprintf(content, static_cast<size_t>(size) + 1, format, arg_ptr);
        va_end(arg_ptr);
        std::cout << ": " << content << std::endl;
		fileOut << content;
        length += size;
        delete []content;
    }
	fileOut << "\n";
	fileOut.flush();

    if(length >= max && max > 0){
        Rotate();
    }

}

void NahidaProject::Logger::Rotate(){
    Close();
    auto timeTicks = time(nullptr);
    auto ptns = localtime(&timeTicks);
    char timeArray[32];
    memset(timeArray, 0, sizeof(timeArray));
    strftime(timeArray, sizeof(timeArray), ".%Y-%m-%d_%H-%M-%S", ptns);
    std::string fileName=fileName+timeArray;
    if(rename(fileName.c_str(),fileName.c_str()) != 0) {
        return;
    }
    Open(fileName);
}

